#include "app_buffer.h"
#include <stdlib.h>
#include <log.h>
#include <string.h>
#include <pthread.h>

/**
 * @brief  初始化buffer
 * @return c缓冲区
 *
 */

 
Buffer *app_buffer_init(int total_size)
{
    // 0   初始化结构体空间
    Buffer *buffer = (Buffer *)malloc(sizeof(Buffer));
    if (buffer == NULL)
    {
        log_error("malloc buffer failed");
        return NULL;
    }

    // 1   缓冲区指针     参数空间大小 进行 malloc
    buffer->ptr = (char *)malloc(total_size);
    if (buffer->ptr == NULL)
    {
        log_error("malloc buffer->ptr failed");
        free(buffer);
        return NULL;
    }

    // 2   空间总长度      参数空间大小
    buffer->total_size = total_size;

    // 3   起始偏移量      0
    buffer->offset = 0;

    // 4    数据长度         0
    buffer->len = 0;

    pthread_mutex_init(&buffer->lock, NULL);

    log_info("buffer_create: %p", buffer);
    return buffer;
}

/**
 * 写入数据
 * @return   0:成功  -1:失败
 * 1 首先判断   写入长度是否大于 剩余可存储长度(空间总长度-数据长度)
              如果大于 直接 报错退出
2   是否能够一次性写入 没有 溢出到开头部分 （一段写 二段写)
     到末尾段的剩余空间=空间总长度-偏移量 –数据长度
       写入长度 <=到末尾段的剩余空间
             则 一段写
                    2.1 (   缓冲区指针 +写入位置（偏移量+数据长度） ，写入数据，写入长度)
                   新的总长度= 总长度+写入长度
             否则  二段写memcpy
                    2.2.1   前半段 写入剩余的尾部空间
            memcpy(   缓冲区指针 +写入位置，写入数据 ，到末尾段的剩余空间）
                    2.2.2  后半段  写入剩余未写入部分
              数据溢出长度=写入长度-到末尾段的剩余空间
            memcpy(缓冲区指针 ，写入数据+到末尾段的剩余空间,数据溢出长度）
                      新的总长度= 总长度+写入长度

 */
int app_buffer_write(Buffer *buffer, const char *write_data, int write_len)
{ // 1 首先判断   写入长度是否大于 剩余可存储长度(空间总长度-数据长度)
    

    //加锁
    pthread_mutex_lock(&buffer->lock);
    //?A
    if (write_len > (buffer->total_size - buffer->len))
    {
        log_error("写入长度大于剩余可存储长度");
        // 解锁
        pthread_mutex_unlock(&buffer->lock);
        return -1;
    }
    //?B
    // 2   是否能够一次性写入 没有 溢出到开头部分 （一段写 二段写)
    //  到末尾段的剩余空间=空间总长度-偏移量 –数据长度
    //    写入长度 <=到末尾段的剩余空间
    int to_end_size = buffer->total_size - buffer->offset - buffer->len;
    //布丁
    if(to_end_size<0)// 可读部分溢出到开头部分 //只可能出现一段写
    {  // 把溢出部分 的负值变正值 作为写入起点
       memcpy(buffer->ptr -to_end_size, write_data, write_len);
    }else if (write_len <= to_end_size)
    { // 一段写
        // 2.1 (   缓冲区指针 +写入位置（偏移量+数据长度） ，写入数据，写入长度)
        memcpy(buffer->ptr + buffer->offset + buffer->len, write_data, write_len);
    }
    else
    { // 2.2.1   前半段 写入剩余的尾部空间
      // memcpy(   缓冲区指针 +写入位置，写入数据 ，到末尾段的剩余空间）
        memcpy(buffer->ptr + buffer->offset + buffer->len, write_data, to_end_size);
        //      2.2.2  后半段  写入剩余未写入部分
        //    数据溢出长度=写入长度-到末尾段的剩余空间
        int overflow_len = write_len - to_end_size;
        // memcpy(缓冲区指针 ，写入数据+到末尾段的剩余空间,数据溢出长度）
        memcpy(buffer->ptr, write_data + to_end_size, overflow_len);
    }
    // 新的总长度= 总长度+写入长度
    //C
    buffer->len += write_len;
    
  
    log_info("write_len:%d,write_data:%.*s",write_len,write_len,write_data);
    log_debug("buffer->len:%d,buffer:%.*s,offset:%d",buffer->len,buffer->total_size,buffer->ptr,buffer->offset );
     //解锁
     pthread_mutex_unlock(&buffer->lock);

}


/**
 * 读取数据
 * @return     -1:失败   非负 实际读取长度
 * 接受读取数据的buffer  read_buffer  ,  要读取的长度 read_size 
   实际能读取的长度 取  read_size和 数据长度的最小值
   判断是否需要分段读取 
       到末尾未读取的长度=总空间长度-偏移量 
       如果要读取的长度<=末尾未读取的长度
     则 一段读取  
memcpy(read_buffer , 缓冲指针+偏移量，读取的长度 ）
偏移量+=读取长度
数据长度-=读取长度
      否则 两段读取
            memcpy(read_buffer,缓冲指针+偏移量,到末尾未读取的长度)
            溢出长度=读取的长度-到末尾未读取的长度
           memcpy(read_buffer+到末尾未读取的长度,缓冲指针,溢出长度)
            数据长度-=读取长度
           偏移量=溢出长度

 * 
 */
int app_buffer_read(Buffer *buffer, char *read_buffer, int read_len)
{       
        //加锁
        pthread_mutex_lock(&buffer->lock);

       // 实际能读取的长度 取  read_len和 数据长度的最小值
       read_len = (read_len < buffer->len) ? read_len : buffer->len;
       //判断是否需要分段读取 
       //到末尾未读取的长度=总空间长度-偏移量 
       int to_end_len = buffer->total_size - buffer->offset;

      // 如果要读取的长度<=末尾未读取的长度
      if(read_len <= to_end_len)
      {
        /**
         * 则 一段读取  
            memcpy(read_buffer , 缓冲指针+偏移量，读取的长度 ）
            偏移量+=读取长度
            数据长度-=读取长度
         */
        memcpy(read_buffer , buffer->ptr + buffer->offset , read_len);
        buffer->offset += read_len;
        if(buffer->offset == buffer->total_size) //补丁：如果已经读完，则重置偏移量
        {
          buffer->offset = 0;
        }

        buffer->len-=read_len;
      }
      else
      {
        //  memcpy(read_buffer,缓冲指针+偏移量,到末尾未读取的长度)
        memcpy(read_buffer,buffer->ptr+buffer->offset,to_end_len);
        //    溢出长度=读取的长度-到末尾未读取的长度
        int overflow_len=read_len-to_end_len;
        //   memcpy(read_buffer+到末尾未读取的长度,缓冲指针,溢出长度)
        memcpy(read_buffer+to_end_len,buffer->ptr,overflow_len);

        //    数据长度-=读取长度
        buffer->len-=read_len;
        //   偏移量=溢出长度
        buffer->offset=overflow_len;

      }
    log_info("read_len:%d,read_buffer:%.*s",read_len,read_len,read_buffer);
    log_debug("buffer->len:%d,buffer:%.*s,offset:%d",buffer->len,buffer->total_size,buffer->ptr,buffer->offset );
     //解锁
     pthread_mutex_unlock(&buffer->lock);
    return read_len;
}


/**
 * 释放buffer
 */
void app_buffer_free(Buffer *buffer)
{
    pthread_mutex_destroy(&buffer->lock);
    free(buffer->ptr);
    free(buffer);
     log_debug("free buffer:%p",buffer);
}